home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 108 / MacAddict108.iso / Software / Internet & Communication / WordPress 1.5.1.dmg / wordpress / xmlrpc.php < prev   
Encoding:
PHP Script  |  2005-05-03  |  36.3 KB  |  1,275 lines

  1. <?php
  2.  
  3. # fix for mozBlog and other cases where '<?xml' isn't on the very first line
  4. $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
  5.  
  6. include('./wp-config.php');
  7. include_once(ABSPATH . WPINC . '/class-IXR.php');
  8.  
  9. // Turn off all warnings and errors.
  10. // error_reporting(0);
  11.  
  12. $post_default_title = ""; // posts submitted via the xmlrpc interface get that title
  13. $post_default_category = 1; // posts submitted via the xmlrpc interface go into that category
  14.  
  15. $xmlrpc_logging = 0;
  16.  
  17. function logIO($io,$msg) {
  18.     global $xmlrpc_logging;
  19.     if ($xmlrpc_logging) {
  20.         $fp = fopen("../xmlrpc.log","a+");
  21.         $date = gmdate("Y-m-d H:i:s ");
  22.         $iot = ($io == "I") ? " Input: " : " Output: ";
  23.         fwrite($fp, "\n\n".$date.$iot.$msg);
  24.         fclose($fp);
  25.     }
  26.     return true;
  27.     }
  28.  
  29. function starify($string) {
  30.     $i = strlen($string);
  31.     return str_repeat('*', $i);
  32. }
  33.  
  34. logIO("I", $HTTP_RAW_POST_DATA);
  35.  
  36.  
  37. function mkdir_p($target) {
  38.     // from php.net/mkdir user contributed notes 
  39.     if (file_exists($target)) {
  40.       if (!is_dir($target)) {
  41.         return false;
  42.       } else {
  43.         return true;
  44.       }
  45.     }
  46.  
  47.     // Attempting to create the directory may clutter up our display.
  48.     if (@mkdir($target)) {
  49.       return true;
  50.     }
  51.  
  52.     // If the above failed, attempt to create the parent node, then try again.
  53.     if (mkdir_p(dirname($target))) {
  54.       return mkdir_p($target);
  55.     }
  56.  
  57.     return false;
  58. }
  59.  
  60.  
  61. class wp_xmlrpc_server extends IXR_Server {
  62.  
  63.     function wp_xmlrpc_server() {
  64.         $this->methods = array(
  65.           // Blogger API
  66.           'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  67.           'blogger.getUserInfo' => 'this:blogger_getUserInfo',
  68.           'blogger.getPost' => 'this:blogger_getPost',
  69.           'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
  70.           'blogger.getTemplate' => 'this:blogger_getTemplate',
  71.           'blogger.setTemplate' => 'this:blogger_setTemplate',
  72.           'blogger.newPost' => 'this:blogger_newPost',
  73.           'blogger.editPost' => 'this:blogger_editPost',
  74.           'blogger.deletePost' => 'this:blogger_deletePost',
  75.  
  76.           // MetaWeblog API (with MT extensions to structs)
  77.           'metaWeblog.newPost' => 'this:mw_newPost',
  78.           'metaWeblog.editPost' => 'this:mw_editPost',
  79.           'metaWeblog.getPost' => 'this:mw_getPost',
  80.           'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
  81.           'metaWeblog.getCategories' => 'this:mw_getCategories',
  82.           'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
  83.  
  84.           // MetaWeblog API aliases for Blogger API
  85.           // see http://www.xmlrpc.com/stories/storyReader$2460
  86.           'metaWeblog.deletePost' => 'this:blogger_deletePost',
  87.           'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
  88.           'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
  89.           'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
  90.  
  91.           // MovableType API
  92.           'mt.getCategoryList' => 'this:mt_getCategoryList',
  93.           'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
  94.           'mt.getPostCategories' => 'this:mt_getPostCategories',
  95.           'mt.setPostCategories' => 'this:mt_setPostCategories',
  96.           'mt.supportedMethods' => 'this:mt_supportedMethods',
  97.           'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
  98.           'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
  99.           'mt.publishPost' => 'this:mt_publishPost',
  100.  
  101.           // PingBack
  102.           'pingback.ping' => 'this:pingback_ping',
  103.           'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
  104.  
  105.           'demo.sayHello' => 'this:sayHello',
  106.           'demo.addTwoNumbers' => 'this:addTwoNumbers'
  107.         );
  108.         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
  109.         $this->IXR_Server($this->methods);
  110.     }
  111.  
  112.     function sayHello($args) {
  113.         return 'Hello!';
  114.     }
  115.  
  116.     function addTwoNumbers($args) {
  117.         $number1 = $args[0];
  118.         $number2 = $args[1];
  119.         return $number1 + $number2;
  120.     }
  121.  
  122.     function login_pass_ok($user_login, $user_pass) {
  123.       if (!user_pass_ok($user_login, $user_pass)) {
  124.         $this->error = new IXR_Error(403, 'Bad login/pass combination.');
  125.         return false;
  126.       }
  127.       return true;
  128.     }
  129.  
  130.  
  131.  
  132.  
  133.     /* Blogger API functions
  134.      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
  135.      */
  136.  
  137.  
  138.     /* blogger.getUsersBlogs will make more sense once we support multiple blogs */
  139.     function blogger_getUsersBlogs($args) {
  140.  
  141.       $user_login = $args[1];
  142.       $user_pass  = $args[2];
  143.  
  144.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  145.         return $this->error;
  146.       }
  147.  
  148.       $user_data = get_userdatabylogin($user_login);
  149.       $is_admin = $user_data->user_level > 3;
  150.  
  151.       $struct = array(
  152.         'isAdmin'  => $is_admin,
  153.         'url'      => get_settings('home') . '/',
  154.         'blogid'   => '1',
  155.         'blogName' => get_settings('blogname')
  156.       );
  157.  
  158.       return array($struct);
  159.     }
  160.  
  161.  
  162.     /* blogger.getUsersInfo gives your client some info about you, so you don't have to */
  163.     function blogger_getUserInfo($args) {
  164.  
  165.       $user_login = $args[1];
  166.       $user_pass  = $args[2];
  167.  
  168.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  169.         return $this->error;
  170.       }
  171.  
  172.       $user_data = get_userdatabylogin($user_login);
  173.  
  174.       $struct = array(
  175.         'nickname'  => $user_data->user_nickname,
  176.         'userid'    => $user_data->ID,
  177.         'url'       => $user_data->user_url,
  178.         'email'     => $user_data->user_email,
  179.         'lastname'  => $user_data->user_lastname,
  180.         'firstname' => $user_data->user_firstname
  181.       );
  182.  
  183.       return $struct;
  184.     }
  185.  
  186.  
  187.     /* blogger.getPost ...gets a post */
  188.     function blogger_getPost($args) {
  189.  
  190.       $post_ID    = $args[1];
  191.       $user_login = $args[2];
  192.       $user_pass  = $args[3];
  193.  
  194.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  195.         return $this->error;
  196.       }
  197.  
  198.       $user_data = get_userdatabylogin($user_login);
  199.       $post_data = wp_get_single_post($post_ID, ARRAY_A);
  200.  
  201.       $categories = implode(',', wp_get_post_cats(1, $post_ID));
  202.  
  203.       $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
  204.       $content .= '<category>'.$categories.'</category>';
  205.       $content .= stripslashes($post_data['post_content']);
  206.  
  207.       $struct = array(
  208.         'userid'    => $post_data['post_author'],
  209.         'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])),
  210.         'content'     => $content,
  211.         'postid'  => $post_data['ID']
  212.       );
  213.  
  214.       return $struct;
  215.     }
  216.  
  217.  
  218.     /* blogger.getRecentPosts ...gets recent posts */
  219.     function blogger_getRecentPosts($args) {
  220.  
  221.       global $wpdb;
  222.  
  223.       $blog_ID    = $args[1]; /* though we don't use it yet */
  224.       $user_login = $args[2];
  225.       $user_pass  = $args[3];
  226.       $num_posts  = $args[4];
  227.  
  228.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  229.         return $this->error;
  230.       }
  231.  
  232.       $posts_list = wp_get_recent_posts($num_posts);
  233.  
  234.       if (!$posts_list) {
  235.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  236.         return $this->error;
  237.       }
  238.  
  239.       foreach ($posts_list as $entry) {
  240.       
  241.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  242.         $categories = implode(',', wp_get_post_cats(1, $entry['ID']));
  243.  
  244.         $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
  245.         $content .= '<category>'.$categories.'</category>';
  246.         $content .= stripslashes($entry['post_content']);
  247.  
  248.         $struct[] = array(
  249.           'userid' => $entry['post_author'],
  250.           'dateCreated' => new IXR_Date($post_date),
  251.           'content' => $content,
  252.           'postid' => $entry['ID'],
  253.         );
  254.  
  255.       }
  256.  
  257.       $recent_posts = array();
  258.       for ($j=0; $j<count($struct); $j++) {
  259.         array_push($recent_posts, $struct[$j]);
  260.       }
  261.  
  262.       return $recent_posts;
  263.     }
  264.  
  265.  
  266.     /* blogger.getTemplate returns your blog_filename */
  267.     function blogger_getTemplate($args) {
  268.  
  269.       $blog_ID    = $args[1];
  270.       $user_login = $args[2];
  271.       $user_pass  = $args[3];
  272.       $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
  273.  
  274.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  275.         return $this->error;
  276.       }
  277.  
  278.       $user_data = get_userdatabylogin($user_login);
  279.  
  280.       if ($user_data->user_level < 3) {
  281.         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
  282.       }
  283.  
  284.       /* warning: here we make the assumption that the weblog's URI is on the same server */
  285.       $filename = get_settings('home') . '/';
  286.       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  287.  
  288.       $f = fopen($filename, 'r');
  289.       $content = fread($f, filesize($filename));
  290.       fclose($f);
  291.  
  292.       /* so it is actually editable with a windows/mac client */
  293.       // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented.     $content = str_replace("\n", "\r\n", $content); 
  294.  
  295.       return $content;
  296.     }
  297.  
  298.  
  299.     /* blogger.setTemplate updates the content of blog_filename */
  300.     function blogger_setTemplate($args) {
  301.  
  302.       $blog_ID    = $args[1];
  303.       $user_login = $args[2];
  304.       $user_pass  = $args[3];
  305.       $content    = $args[4];
  306.       $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
  307.  
  308.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  309.         return $this->error;
  310.       }
  311.  
  312.       $user_data = get_userdatabylogin($user_login);
  313.  
  314.       if ($user_data->user_level < 3) {
  315.         return new IXR_Error(401, 'Sorry, users whose level is less than 3, can not edit the template.');
  316.       }
  317.  
  318.       /* warning: here we make the assumption that the weblog's URI is on the same server */
  319.       $filename = get_settings('home') . '/';
  320.       $filename = preg_replace('#http://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
  321.  
  322.       if ($f = fopen($filename, 'w+')) {
  323.         fwrite($f, $content);
  324.         fclose($f);
  325.       } else {
  326.         return new IXR_Error(500, 'Either the file is not writable, or something wrong happened. The file has not been updated.');
  327.       }
  328.  
  329.       return true;
  330.     }
  331.  
  332.  
  333.     /* blogger.newPost ...creates a new post */
  334.     function blogger_newPost($args) {
  335.  
  336.       global $wpdb;
  337.  
  338.       $blog_ID    = $args[1]; /* though we don't use it yet */
  339.       $user_login = $args[2];
  340.       $user_pass  = $args[3];
  341.       $content    = $args[4];
  342.       $publish    = $args[5];
  343.  
  344.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  345.         return $this->error;
  346.       }
  347.  
  348.       $user_data = get_userdatabylogin($user_login);
  349.       if (!user_can_create_post($user_data->ID, $blog_ID)) {
  350.         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
  351.       }
  352.  
  353.       $post_status = ($publish) ? 'publish' : 'draft';
  354.  
  355.       $post_author = $user_data->ID;
  356.  
  357.       $post_title = xmlrpc_getposttitle($content);
  358.       $post_category = xmlrpc_getpostcategory($content);
  359.  
  360.       $content = xmlrpc_removepostdata($content);
  361.       $post_content = apply_filters( 'content_save_pre', $content );
  362.  
  363.       $post_date = current_time('mysql');
  364.       $post_date_gmt = current_time('mysql', 1);
  365.  
  366.       $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
  367.  
  368.       $post_ID = wp_insert_post($post_data);
  369.  
  370.       if (!$post_ID) {
  371.         return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.');
  372.       }
  373.  
  374.       logIO('O', "Posted ! ID: $post_ID");
  375.  
  376.       return $post_ID;
  377.     }
  378.  
  379.  
  380.     /* blogger.editPost ...edits a post */
  381.     function blogger_editPost($args) {
  382.  
  383.       global $wpdb;
  384.  
  385.       $post_ID     = $args[1];
  386.       $user_login  = $args[2];
  387.       $user_pass   = $args[3];
  388.       $new_content = $args[4];
  389.       $publish     = $args[5];
  390.  
  391.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  392.         return $this->error;
  393.       }
  394.  
  395.       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  396.  
  397.       if (!$actual_post) {
  398.           return new IXR_Error(404, 'Sorry, no such post.');
  399.       }
  400.  
  401.       $post_author_data = get_userdata($actual_post['post_author']);
  402.       $user_data = get_userdatabylogin($user_login);
  403.  
  404.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  405.         return new IXR_Error(401, 'Sorry, you do not have the right to edit this post.');
  406.       }
  407.  
  408.       extract($actual_post);
  409.       $content = $newcontent;
  410.  
  411.       $post_title = xmlrpc_getposttitle($content);
  412.       $post_category = xmlrpc_getpostcategory($content);
  413.  
  414.       $content = xmlrpc_removepostdata($content);
  415.       $post_content = apply_filters( 'content_save_pre', $content );
  416.  
  417.       $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
  418.  
  419.       $result = wp_update_post($postdata);
  420.  
  421.       if (!$result) {
  422.           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be edited.');
  423.       }
  424.  
  425.       return true;
  426.     }
  427.  
  428.  
  429.     /* blogger.deletePost ...deletes a post */
  430.     function blogger_deletePost($args) {
  431.  
  432.       global $wpdb;
  433.  
  434.       $post_ID     = $args[1];
  435.       $user_login  = $args[2];
  436.       $user_pass   = $args[3];
  437.       $publish     = $args[4];
  438.  
  439.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  440.         return $this->error;
  441.       }
  442.  
  443.       $actual_post = wp_get_single_post($post_ID,ARRAY_A);
  444.  
  445.       if (!$actual_post) {
  446.           return new IXR_Error(404, 'Sorry, no such post.');
  447.       }
  448.  
  449.       $user_data = get_userdatabylogin($user_login);
  450.  
  451.       if (!user_can_delete_post($user_data->ID, $post_ID)) {
  452.         return new IXR_Error(401, 'Sorry, you do not have the right to delete this post.');
  453.       }
  454.  
  455.       $result = wp_delete_post($post_ID);
  456.  
  457.       if (!$result) {
  458.           return new IXR_Error(500, 'For some strange yet very annoying reason, this post could not be deleted.');
  459.       }
  460.  
  461.       return true;
  462.     }
  463.  
  464.  
  465.  
  466.     /* MetaWeblog API functions
  467.      * specs on wherever Dave Winer wants them to be
  468.      */
  469.  
  470.     /* metaweblog.newPost creates a post */
  471.     function mw_newPost($args) {
  472.  
  473.       global $wpdb;
  474.  
  475.       $blog_ID     = $args[0]; // we will support this in the near future
  476.       $user_login  = $args[1];
  477.       $user_pass   = $args[2];
  478.       $content_struct = $args[3];
  479.       $publish     = $args[4];
  480.  
  481.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  482.         return $this->error;
  483.       }
  484.  
  485.       $user_data = get_userdatabylogin($user_login);
  486.       if (!user_can_create_post($user_data->ID, $blog_ID)) {
  487.         return new IXR_Error(401, 'Sorry, you can not post on this weblog or category.');
  488.       }
  489.  
  490.       $post_author = $user_data->ID;
  491.  
  492.       $post_title = $content_struct['title'];
  493.       $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  494.       $post_status = $publish ? 'publish' : 'draft';
  495.  
  496.       $post_excerpt = $content_struct['mt_excerpt'];
  497.       $post_more = $content_struct['mt_text_more'];
  498.  
  499.       $comment_status = (empty($content_struct['mt_allow_comments'])) ?
  500.         get_settings('default_comment_status')
  501.         : $content_struct['mt_allow_comments'];
  502.  
  503.       $ping_status = (empty($content_struct['mt_allow_pings'])) ?
  504.         get_settings('default_ping_status')
  505.         : $content_struct['mt_allow_pings'];
  506.  
  507.       if ($post_more) {
  508.         $post_content = $post_content . "\n<!--more-->\n" . $post_more;
  509.       }
  510.         
  511.       // Do some timestamp voodoo
  512.       $dateCreatedd = $content_struct['dateCreated'];
  513.       if (!empty($dateCreatedd)) {
  514.         $dateCreated = $dateCreatedd->getIso();
  515.         $post_date     = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  516.         $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  517.       } else {
  518.         $post_date     = current_time('mysql');
  519.         $post_date_gmt = current_time('mysql', 1);
  520.       }
  521.  
  522.       $catnames = $content_struct['categories'];
  523.       logIO('O', 'Post cats: ' . printr($catnames,true));
  524.       $post_category = array();
  525.  
  526.       if (is_array($catnames)) {
  527.         foreach ($catnames as $cat) {
  528.           $post_category[] = get_cat_ID($cat);
  529.         }
  530.       } else {
  531.         $post_category[] = 1;
  532.       }
  533.         
  534.       // We've got all the data -- post it:
  535.       $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status');
  536.  
  537.       $post_ID = wp_insert_post($postdata);
  538.  
  539.       if (!$post_ID) {
  540.         return new IXR_Error(500, 'Sorry, your entry could not be posted. Something wrong happened.');
  541.       }
  542.  
  543.       logIO('O', "Posted ! ID: $post_ID");
  544.  
  545.       // FIXME: do we pingback always? pingback($content, $post_ID);
  546.       trackback_url_list($content_struct['mt_tb_ping_urls'],$post_ID);
  547.  
  548.       return strval($post_ID);
  549.     }
  550.  
  551.  
  552.     /* metaweblog.editPost ...edits a post */
  553.     function mw_editPost($args) {
  554.  
  555.       global $wpdb;
  556.  
  557.       $post_ID     = $args[0];
  558.       $user_login  = $args[1];
  559.       $user_pass   = $args[2];
  560.       $content_struct = $args[3];
  561.       $publish     = $args[4];
  562.  
  563.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  564.         return $this->error;
  565.       }
  566.  
  567.       $user_data = get_userdatabylogin($user_login);
  568.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  569.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  570.       }
  571.  
  572.       $postdata = wp_get_single_post($post_ID, ARRAY_A);
  573.       extract($postdata);
  574.  
  575.       $post_title = $content_struct['title'];
  576.       $post_content = apply_filters( 'content_save_pre', $content_struct['description'] );
  577.       $catnames = $content_struct['categories'];
  578.         
  579.       if (is_array($catnames)) {
  580.         foreach ($catnames as $cat) {
  581.           $post_category[] = get_cat_ID($cat);
  582.         }
  583.       } else {
  584.         $post_category[] = 1;
  585.       }
  586.  
  587.       $post_excerpt = $content_struct['mt_excerpt'];
  588.       $post_more = $content_struct['mt_text_more'];
  589.       $post_status = $publish ? 'publish' : 'draft';
  590.  
  591.       if ($post_more) {
  592.         $post_content = $post_content . "\n<!--more-->\n" . $post_more;
  593.       }
  594.  
  595.       $comment_status = (empty($content_struct['mt_allow_comments'])) ?
  596.         get_settings('default_comment_status')
  597.         : $content_struct['mt_allow_comments'];
  598.  
  599.       $ping_status = (empty($content_struct['mt_allow_pings'])) ?
  600.         get_settings('default_ping_status')
  601.         : $content_struct['mt_allow_pings'];
  602.  
  603.       // Do some timestamp voodoo
  604.       $dateCreatedd = $content_struct['dateCreated'];
  605.       if (!empty($dateCreatedd)) {
  606.         $dateCreated = $dateCreatedd->getIso();
  607.         $post_date     = get_date_from_gmt(iso8601_to_datetime($dateCreated));
  608.         $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
  609.       } else {
  610.         $post_date     = $postdata['post_date'];
  611.         $post_date_gmt = $postdata['post_date_gmt'];
  612.       }
  613.  
  614.       // We've got all the data -- post it:
  615.       $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt');
  616.  
  617.       $post_ID = wp_update_post($newpost);
  618.       if (!$post_ID) {
  619.         return new IXR_Error(500, 'Sorry, your entry could not be edited. Something wrong happened.');
  620.       }
  621.  
  622.       logIO('O',"(MW) Edited ! ID: $post_ID");
  623.  
  624.       // FIXME: do we pingback always? pingback($content, $post_ID);
  625.       trackback_url_list($content_struct['mt_tb_ping_urls'], $post_ID);
  626.  
  627.       return true;
  628.     }
  629.  
  630.  
  631.     /* metaweblog.getPost ...returns a post */
  632.     function mw_getPost($args) {
  633.  
  634.       global $wpdb;
  635.  
  636.       $post_ID     = $args[0];
  637.       $user_login  = $args[1];
  638.       $user_pass   = $args[2];
  639.  
  640.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  641.         return $this->error;
  642.       }
  643.  
  644.       $postdata = wp_get_single_post($post_ID, ARRAY_A);
  645.  
  646.       if ($postdata['post_date'] != '') {
  647.  
  648.         $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date']);
  649.  
  650.         $categories = array();
  651.         $catids = wp_get_post_cats('', $post_ID);
  652.         foreach($catids as $catid) {
  653.           $categories[] = get_cat_name($catid);
  654.         }
  655.  
  656.         $post = get_extended($postdata['post_content']);
  657.         $link = post_permalink($postdata['ID']);
  658.  
  659.         $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
  660.         $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
  661.  
  662.         $resp = array(
  663.           'dateCreated' => new IXR_Date($post_date),
  664.           'userid' => $postdata['post_author'],
  665.           'postid' => $postdata['ID'],
  666.           'description' => $post['main'],
  667.           'title' => $postdata['post_title'],
  668.           'link' => $link,
  669.           'permaLink' => $link,
  670. // commented out because no other tool seems to use this
  671. //          'content' => $entry['post_content'],
  672.           'categories' => $categories,
  673.           'mt_excerpt' => $postdata['post_excerpt'],
  674.           'mt_text_more' => $post['extended'],
  675.           'mt_allow_comments' => $allow_comments,
  676.           'mt_allow_pings' => $allow_pings
  677.         );
  678.  
  679.         return $resp;
  680.       } else {
  681.           return new IXR_Error(404, 'Sorry, no such post.');
  682.       }
  683.     }
  684.  
  685.  
  686.     /* metaweblog.getRecentPosts ...returns recent posts */
  687.     function mw_getRecentPosts($args) {
  688.  
  689.       $blog_ID     = $args[0];
  690.       $user_login  = $args[1];
  691.       $user_pass   = $args[2];
  692.       $num_posts   = $args[3];
  693.  
  694.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  695.         return $this->error;
  696.       }
  697.  
  698.       $posts_list = wp_get_recent_posts($num_posts);
  699.  
  700.       if (!$posts_list) {
  701.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  702.         return $this->error;
  703.       }
  704.  
  705.       foreach ($posts_list as $entry) {
  706.       
  707.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  708.         $categories = array();
  709.         $catids = wp_get_post_cats('', $entry['ID']);
  710.         foreach($catids as $catid) {
  711.           $categories[] = get_cat_name($catid);
  712.         }
  713.  
  714.         $post = get_extended($entry['post_content']);
  715.         $link = post_permalink($entry['ID']);
  716.  
  717.         $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
  718.         $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
  719.  
  720.         $struct[] = array(
  721.           'dateCreated' => new IXR_Date($post_date),
  722.           'userid' => $entry['post_author'],
  723.           'postid' => $entry['ID'],
  724.           'description' => $post['main'],
  725.           'title' => $entry['post_title'],
  726.           'link' => $link,
  727.           'permaLink' => $link,
  728. // commented out because no other tool seems to use this
  729. //          'content' => $entry['post_content'],
  730.           'categories' => $categories,
  731.           'mt_excerpt' => $entry['post_excerpt'],
  732.           'mt_text_more' => $post['extended'],
  733.           'mt_allow_comments' => $allow_comments,
  734.           'mt_allow_pings' => $allow_pings
  735.         );
  736.  
  737.       }
  738.  
  739.       $recent_posts = array();
  740.       for ($j=0; $j<count($struct); $j++) {
  741.         array_push($recent_posts, $struct[$j]);
  742.       }
  743.       
  744.       return $recent_posts;
  745.     }
  746.  
  747.  
  748.     /* metaweblog.getCategories ...returns the list of categories on a given weblog */
  749.     function mw_getCategories($args) {
  750.  
  751.       global $wpdb;
  752.  
  753.       $blog_ID     = $args[0];
  754.       $user_login  = $args[1];
  755.       $user_pass   = $args[2];
  756.  
  757.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  758.         return $this->error;
  759.       }
  760.  
  761.       $categories_struct = array();
  762.  
  763.       // FIXME: can we avoid using direct SQL there?
  764.       if ($cats = $wpdb->get_results("SELECT cat_ID,cat_name FROM $wpdb->categories", ARRAY_A)) {
  765.         foreach ($cats as $cat) {
  766.           $struct['categoryId'] = $cat['cat_ID'];
  767.           $struct['description'] = $cat['cat_name'];
  768.           $struct['categoryName'] = $cat['cat_name'];
  769.           $struct['htmlUrl'] = wp_specialchars(get_category_link($cat['cat_ID']));
  770.           $struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat['cat_ID'], $cat['cat_name']));
  771.  
  772.           $categories_struct[] = $struct;
  773.         }
  774.       }
  775.  
  776.       return $categories_struct;
  777.     }
  778.  
  779.  
  780.     /* metaweblog.newMediaObject uploads a file, following your settings */
  781.     function mw_newMediaObject($args) {
  782.       // adapted from a patch by Johann Richard
  783.       // http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
  784.  
  785.       $blog_ID     = $args[0];
  786.       $user_login  = $args[1];
  787.       $user_pass   = $args[2];
  788.       $data        = $args[3];
  789.  
  790.       $name = $data['name'];
  791.       $type = $data['type'];
  792.       $bits = $data['bits'];
  793.  
  794.       $file_realpath = get_settings('fileupload_realpath'); 
  795.       $file_url = get_settings('fileupload_url');
  796.  
  797.       logIO('O', '(MW) Received '.strlen($bits).' bytes');
  798.  
  799.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  800.         return $this->error;
  801.       }
  802.  
  803.       $user_data = get_userdatabylogin($user_login);
  804.  
  805.       if(!get_settings('use_fileupload')) {
  806.         // Uploads not allowed
  807.         logIO('O', '(MW) Uploads not allowed');
  808.         $this->error = new IXR_Error(405, 'No uploads allowed for this site.');
  809.         return $this->error;
  810.       } 
  811.  
  812.       if(get_settings('fileupload_minlevel') > $user_data->user_level) {
  813.         // User has not enough privileges
  814.         logIO('O', '(MW) Not enough privilege: user level too low');
  815.         $this->error = new IXR_Error(401, 'You are not allowed to upload files to this site.');
  816.         return $this->error;
  817.       }
  818.  
  819.       if(trim($file_realpath) == '' || trim($file_url) == '' ) {
  820.         // WordPress is not correctly configured
  821.         logIO('O', '(MW) Bad configuration. Real/URL path not defined');
  822.         $this->error = new IXR_Error(500, 'Please configure WordPress with valid paths for file upload.');
  823.         return $this->error;
  824.       }
  825.  
  826.       $prefix = '/';
  827.  
  828.       if(!empty($name)) {
  829.         // Create the path
  830.         $localpath = $file_realpath.$prefix.$name;
  831.         $url = $file_url.$prefix.$name;
  832.  
  833.         if (mkdir_p(dirname($localpath))) {
  834.  
  835.           /* encode & write data (binary) */
  836.           $ifp = fopen($localpath, 'wb');
  837.           $success = fwrite($ifp, $bits);
  838.           fclose($ifp);
  839.           @chmod($localpath, 0666);
  840.  
  841.           if($success) {
  842.             $resp = array('url' => $url);
  843.             return $resp;
  844.           } else {
  845.             logIO('O', '(MW) Could not write file '.$name.' to '.$localpath);
  846.             return new IXR_Error(500, 'Could not write file '.$name);
  847.           }
  848.  
  849.         } else {
  850.           return new IXR_Error(500, 'Could not create directories for '.$name);
  851.         }
  852.       }
  853.     }
  854.  
  855.  
  856.  
  857.     /* MovableType API functions
  858.      * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
  859.      */
  860.  
  861.     /* mt.getRecentPostTitles ...returns recent posts' titles */
  862.     function mt_getRecentPostTitles($args) {
  863.  
  864.       $blog_ID     = $args[0];
  865.       $user_login  = $args[1];
  866.       $user_pass   = $args[2];
  867.       $num_posts   = $args[3];
  868.  
  869.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  870.         return $this->error;
  871.       }
  872.  
  873.       $posts_list = wp_get_recent_posts($num_posts);
  874.  
  875.       if (!$posts_list) {
  876.         $this->error = new IXR_Error(500, 'Either there are no posts, or something went wrong.');
  877.         return $this->error;
  878.       }
  879.  
  880.       foreach ($posts_list as $entry) {
  881.       
  882.         $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']);
  883.  
  884.         $struct[] = array(
  885.           'dateCreated' => new IXR_Date($post_date),
  886.           'userid' => $entry['post_author'],
  887.           'postid' => $entry['ID'],
  888.           'title' => $entry['post_title'],
  889.         );
  890.  
  891.       }
  892.  
  893.       $recent_posts = array();
  894.       for ($j=0; $j<count($struct); $j++) {
  895.         array_push($recent_posts, $struct[$j]);
  896.       }
  897.       
  898.       return $recent_posts;
  899.     }
  900.  
  901.  
  902.     /* mt.getCategoryList ...returns the list of categories on a given weblog */
  903.     function mt_getCategoryList($args) {
  904.  
  905.       global $wpdb;
  906.  
  907.       $blog_ID     = $args[0];
  908.       $user_login  = $args[1];
  909.       $user_pass   = $args[2];
  910.  
  911.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  912.         return $this->error;
  913.       }
  914.  
  915.       $categories_struct = array();
  916.  
  917.       // FIXME: can we avoid using direct SQL there?
  918.       if ($cats = $wpdb->get_results("SELECT cat_ID, cat_name FROM $wpdb->categories", ARRAY_A)) {
  919.         foreach ($cats as $cat) {
  920.           $struct['categoryId'] = $cat['cat_ID'];
  921.           $struct['categoryName'] = $cat['cat_name'];
  922.  
  923.           $categories_struct[] = $struct;
  924.         }
  925.       }
  926.  
  927.       return $categories_struct;
  928.     }
  929.  
  930.  
  931.     /* mt.getPostCategories ...returns a post's categories */
  932.     function mt_getPostCategories($args) {
  933.  
  934.       $post_ID     = $args[0];
  935.       $user_login  = $args[1];
  936.       $user_pass   = $args[2];
  937.  
  938.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  939.         return $this->error;
  940.       }
  941.  
  942.       $categories = array();
  943.       $catids = wp_get_post_cats('', intval($post_ID));
  944.       // first listed category will be the primary category
  945.       $isPrimary = true;
  946.       foreach($catids as $catid) {
  947.         $categories[] = array(
  948.           'categoryName' => get_cat_name($catid),
  949.           'categoryId' => $catid,
  950.           'isPrimary' => $isPrimary
  951.         );
  952.         $isPrimary = false;
  953.       }
  954.  
  955.       return $categories;
  956.     }
  957.  
  958.  
  959.     /* mt.setPostCategories ...sets a post's categories */
  960.     function mt_setPostCategories($args) {
  961.  
  962.       $post_ID     = $args[0];
  963.       $user_login  = $args[1];
  964.       $user_pass   = $args[2];
  965.       $categories  = $args[3];
  966.  
  967.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  968.         return $this->error;
  969.       }
  970.  
  971.       $user_data = get_userdatabylogin($user_login);
  972.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  973.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  974.       }
  975.  
  976.       foreach($categories as $cat) {
  977.         $catids[] = $cat['categoryId'];
  978.       }
  979.     
  980.       wp_set_post_cats('', $post_ID, $catids);
  981.  
  982.       return true;
  983.     }
  984.  
  985.  
  986.     /* mt.supportedMethods ...returns an array of methods supported by this server */
  987.     function mt_supportedMethods($args) {
  988.  
  989.       $supported_methods = array();
  990.       foreach($this->methods as $key=>$value) {
  991.         $supported_methods[] = $key;
  992.       }
  993.  
  994.       return $supported_methods;
  995.     }
  996.  
  997.  
  998.     /* mt.supportedTextFilters ...returns an empty array because we don't
  999.        support per-post text filters yet */
  1000.     function mt_supportedTextFilters($args) {
  1001.       return array();
  1002.     }
  1003.  
  1004.  
  1005.     /* mt.getTrackbackPings ...returns trackbacks sent to a given post */
  1006.     function mt_getTrackbackPings($args) {
  1007.  
  1008.       global $wpdb;
  1009.  
  1010.       $post_ID = intval($args);
  1011.  
  1012.       $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  1013.  
  1014.       if (!$actual_post) {
  1015.           return new IXR_Error(404, 'Sorry, no such post.');
  1016.       }
  1017.  
  1018.       $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID");
  1019.  
  1020.       if (!$comments) {
  1021.           return array();
  1022.       }
  1023.  
  1024.       $trackback_pings = array();
  1025.       foreach($comments as $comment) {
  1026.         if ( 'trackback' == $comment->comment_type ) {
  1027.           $content = $comment->comment_content;
  1028.           $title = substr($content, 8, (strpos($content, '</strong>') - 8));
  1029.           $trackback_pings[] = array(
  1030.             'pingTitle' => $title,
  1031.             'pingURL'   => $comment->comment_author_url,
  1032.             'pingIP'    => $comment->comment_author_IP
  1033.           );
  1034.         }
  1035.       }
  1036.  
  1037.       return $trackback_pings;
  1038.     }
  1039.  
  1040.  
  1041.     /* mt.publishPost ...sets a post's publish status to 'publish' */
  1042.     function mt_publishPost($args) {
  1043.  
  1044.       $post_ID     = $args[0];
  1045.       $user_login  = $args[1];
  1046.       $user_pass   = $args[2];
  1047.  
  1048.       if (!$this->login_pass_ok($user_login, $user_pass)) {
  1049.         return $this->error;
  1050.       }
  1051.  
  1052.       $user_data = get_userdatabylogin($user_login);
  1053.       if (!user_can_edit_post($user_data->ID, $post_ID)) {
  1054.         return new IXR_Error(401, 'Sorry, you can not edit this post.');
  1055.       }
  1056.  
  1057.       $postdata = wp_get_single_post($post_ID,ARRAY_A);
  1058.  
  1059.       $postdata['post_status'] = 'publish';
  1060.  
  1061.       // retain old cats
  1062.       $cats = wp_get_post_cats('',$post_ID);
  1063.       $postdata['post_category'] = $cats;
  1064.  
  1065.       $result = wp_update_post($postdata);
  1066.  
  1067.       return $result;
  1068.     }
  1069.  
  1070.  
  1071.  
  1072.     /* PingBack functions
  1073.      * specs on www.hixie.ch/specs/pingback/pingback
  1074.      */
  1075.  
  1076.     /* pingback.ping gets a pingback and registers it */
  1077.     function pingback_ping($args) {
  1078.         // original code by Mort (http://mort.mine.nu:8080 -- site seems dead)
  1079.         // refactored to return error codes and avoid deep ifififif headaches
  1080.         global $wpdb, $wp_version; 
  1081.  
  1082.         $pagelinkedfrom = $args[0];
  1083.         $pagelinkedto   = $args[1];
  1084.  
  1085.         $title = '';
  1086.  
  1087.         $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
  1088.         $pagelinkedto   = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedto);
  1089.  
  1090.         $error_code = -1;
  1091.  
  1092.         // Check if the page linked to is in our site
  1093.         $pos1 = strpos($pagelinkedto, str_replace('http://', '', str_replace('www.', '', get_settings('home'))));
  1094.         if(!$pos1) {
  1095.               return new IXR_Error(0, '');
  1096.         }
  1097.  
  1098.  
  1099.         // let's find which post is linked to
  1100.         // FIXME: does url_to_postid() cover all these cases already?
  1101.         //        if so, then let's use it and drop the old code.
  1102.         $urltest = parse_url($pagelinkedto);
  1103.         if ($post_ID = url_to_postid($pagelinkedto)) {
  1104.             $way = 'url_to_postid()';
  1105.         } elseif (preg_match('#p/[0-9]{1,}#', $urltest['path'], $match)) {
  1106.             // the path defines the post_ID (archives/p/XXXX)
  1107.             $blah = explode('/', $match[0]);
  1108.             $post_ID = $blah[1];
  1109.             $way = 'from the path';
  1110.         } elseif (preg_match('#p=[0-9]{1,}#', $urltest['query'], $match)) {
  1111.             // the querystring defines the post_ID (?p=XXXX)
  1112.             $blah = explode('=', $match[0]);
  1113.             $post_ID = $blah[1];
  1114.             $way = 'from the querystring';
  1115.         } elseif (isset($urltest['fragment'])) {
  1116.             // an #anchor is there, it's either...
  1117.             if (intval($urltest['fragment'])) {
  1118.                 // ...an integer #XXXX (simpliest case)
  1119.                 $post_ID = $urltest['fragment'];
  1120.                 $way = 'from the fragment (numeric)';
  1121.             } elseif (preg_match('/post-[0-9]+/',$urltest['fragment'])) {
  1122.                 // ...a post id in the form 'post-###'
  1123.                 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
  1124.                 $way = 'from the fragment (post-###)';
  1125.             } elseif (is_string($urltest['fragment'])) {
  1126.                 // ...or a string #title, a little more complicated
  1127.                 $title = preg_replace('/[^a-zA-Z0-9]/', '.', $urltest['fragment']);
  1128.                 $sql = "SELECT ID FROM $wpdb->posts WHERE post_title RLIKE '$title'";
  1129.                 if (! ($post_ID = $wpdb->get_var($sql)) ) {
  1130.                     // returning unknown error '0' is better than die()ing
  1131.                       return new IXR_Error(0, '');
  1132.                 }
  1133.                 $way = 'from the fragment (title)';
  1134.             }
  1135.         } else {
  1136.             // TODO: Attempt to extract a post ID from the given URL
  1137.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1138.         }
  1139.  
  1140.  
  1141.         logIO("O","(PB) URI='$pagelinkedto' ID='$post_ID' Found='$way'");
  1142.  
  1143.         $sql = 'SELECT post_author FROM '.$wpdb->posts.' WHERE ID = '.$post_ID;
  1144.         $result = $wpdb->get_results($sql);
  1145.  
  1146.         if (!$wpdb->num_rows) {
  1147.             // Post_ID not found
  1148.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1149.         }
  1150.  
  1151.  
  1152.         // Let's check that the remote site didn't already pingback this entry
  1153.         $result = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_post_ID = '$post_ID' AND comment_author_url = '$pagelinkedfrom'");
  1154.  
  1155.         if ($wpdb->num_rows) {
  1156.             // We already have a Pingback from this URL
  1157.               return new IXR_Error(48, 'The pingback has already been registered.');
  1158.         }
  1159.  
  1160.  
  1161.         // very stupid, but gives time to the 'from' server to publish !
  1162.         sleep(1);
  1163.  
  1164.         // Let's check the remote site
  1165.         $linea = wp_remote_fopen( $pagelinkedfrom );
  1166.         if ( !$linea )
  1167.               return new IXR_Error(16, 'The source URI does not exist.');
  1168.  
  1169.         // Work around bug in strip_tags():
  1170.         $linea = str_replace('<!DOCTYPE','<DOCTYPE',$linea);
  1171.         $linea = strip_tags($linea, '<title><a>');
  1172.         $linea = strip_all_but_one_link($linea, $pagelinkedto);
  1173.         // I don't think we need this? -- emc3
  1174.         //$linea = preg_replace('#&([^amp\;])#is', '&$1', $linea);
  1175.         if ( empty($matchtitle) ) {
  1176.             preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
  1177.         }
  1178.         $pos2 = strpos($linea, $pagelinkedto);
  1179.         $pos3 = strpos($linea, str_replace('http://www.', 'http://', $pagelinkedto));
  1180.         if (is_integer($pos2) || is_integer($pos3)) {
  1181.             // The page really links to us :)
  1182.             $pos4 = (is_integer($pos2)) ? $pos2 : $pos3;
  1183.             $start = $pos4-100;
  1184.             $context = substr($linea, $start, 250);
  1185.             $context = str_replace("\n", ' ', $context);
  1186.             $context = str_replace('&', '&', $context);
  1187.         }
  1188.                     
  1189.         fclose($fp);
  1190.  
  1191.         if (empty($context)) {
  1192.             // URL pattern not found
  1193.               return new IXR_Error(17, 'The source URI does not contain a link to the target URI, and so cannot be used as a source.');
  1194.         }
  1195.  
  1196.  
  1197.         // Check if pings are on
  1198.         $pingstatus = $wpdb->get_var("SELECT ping_status FROM $wpdb->posts WHERE ID = $post_ID");
  1199.         if ('closed' == $pingstatus) {
  1200.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1201.         }
  1202.  
  1203.  
  1204.         $pagelinkedfrom = preg_replace('#&([^amp\;])#is', '&$1', $pagelinkedfrom);
  1205.         $title = (!strlen($matchtitle[1])) ? $pagelinkedfrom : $matchtitle[1];
  1206.         $original_context = strip_tags($context);
  1207.         $context = '[...] ';
  1208.         $context .= wp_specialchars($original_context);
  1209.         $context .= ' [...]';
  1210.         $original_pagelinkedfrom = $pagelinkedfrom;
  1211.         $pagelinkedfrom = addslashes($pagelinkedfrom);
  1212.         $original_title = $title;
  1213.  
  1214.         $comment_post_ID = $post_ID;
  1215.         $comment_author = $title;
  1216.         $comment_author_url = $pagelinkedfrom;
  1217.         $comment_content = $context;
  1218.         $comment_type = 'pingback';
  1219.  
  1220.         $pingstatus = $wpdb->get_var("SELECT ping_status FROM $wpdb->posts WHERE ID = $post_ID");
  1221.     
  1222.         if ('open' != $pingstatus)
  1223.             die('Sorry, pingbacks are closed for this item.');
  1224.  
  1225.         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type');
  1226.  
  1227.         wp_new_comment($commentdata);
  1228.         do_action('pingback_post', $wpdb->insert_id);
  1229.         
  1230.         return "Pingback from $pagelinkedfrom to $pagelinkedto registered. Keep the web talking! :-)";
  1231.     }
  1232.  
  1233.  
  1234.     /* pingback.extensions.getPingbacks returns an array of URLs
  1235.        that pingbacked the given URL
  1236.        specs on http://www.aquarionics.com/misc/archives/blogite/0198.html */
  1237.     function pingback_extensions_getPingbacks($args) {
  1238.  
  1239.         global $wpdb;
  1240.  
  1241.         $url = $args;
  1242.  
  1243.         $post_ID = url_to_postid($url);
  1244.         if (!$post_ID) {
  1245.             // We aren't sure that the resource is available and/or pingback enabled
  1246.               return new IXR_Error(33, 'The specified target URI cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.');
  1247.         }
  1248.  
  1249.         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
  1250.  
  1251.         if (!$actual_post) {
  1252.             // No such post = resource not found
  1253.               return new IXR_Error(32, 'The specified target URI does not exist.');
  1254.         }
  1255.  
  1256.         $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID");
  1257.  
  1258.         if (!$comments) {
  1259.             return array();
  1260.         }
  1261.  
  1262.         $pingbacks = array();
  1263.         foreach($comments as $comment) {
  1264.             if ( 'pingback' == $comment->comment_type )
  1265.                 $pingbacks[] = $comment->comment_author_url;
  1266.         }
  1267.  
  1268.         return $pingbacks;
  1269.     }
  1270. }
  1271.  
  1272.  
  1273. $wp_xmlrpc_server = new wp_xmlrpc_server();
  1274.  
  1275. ?>